﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Tulip.Rules.CodeGen
{
    using Engine.Models.ClosedWorld;
    using Models.ClosedWorld;

    /// <summary>
    /// A library of helper code for code generation.
    /// </summary>
    public static class Helpers
    {
        public static string GenerateInvocation(MemberDef mbrDef, bool noThis, Dictionary<string, string> args)
        {
            var qualifier = string.Empty;
            var invocation = string.Empty;
            var argBuilder = new StringBuilder();

            Func<string> genParamStrings =
                () =>
                {
                    argBuilder.Clear();

                    if (mbrDef.Parameters != null)
                    {
                        var isArgs = false;

                        foreach (var paramDef in mbrDef.Parameters.Where((p) => !p.Return && !p.Params))
                        {
                            string argValue;

                            // We will assume that, if the arg value is missing,
                            // this is an optional parameter.
                            if (!args.TryGetValue(paramDef.Name, out argValue)) continue;

                            if (isArgs)
                            {
                                argBuilder.Append(", ");
                            }
                            else
                            {
                                isArgs = true;
                            }
                                  
                            // We will assume that the string representation of the 
                            // argument value contains any necessary delimiters, suffixes,
                            // etc. (e.g., quotes for string literals).
                            argBuilder.Append(paramDef.Name);
                            argBuilder.Append(": ");

                            if (paramDef.ByRef)
                            {
                                argBuilder.Append("ref ");
                            }
                            else if (paramDef.Out)
                            {
                                argBuilder.Append("out ");
                            }

                            argBuilder.Append(argValue);
                        }

                        foreach (var paramDef in mbrDef.Parameters.Where((p) => p.Params))
                        {

                        }

                        // what about indexers?
                    }

                    return argBuilder.ToString();
                };

            switch (mbrDef.BoundMemberKind)
            {
                case MemberKind.Property:
                case MemberKind.PropertyGet:
                case MemberKind.Field:
                case MemberKind.FieldReadOnly:
                case MemberKind.Const:
                // case MemberKind.Event:  // Events cannot be invoked from outside the containing class
                    invocation = mbrDef.BoundMemberName;
                    break;
                case MemberKind.Constructor:
                    invocation = "new ";
                    goto case MemberKind.Method;
                case MemberKind.Method:
                    invocation += mbrDef.BoundMemberTypeName + 
                        "(" + 
                        genParamStrings() + 
                        ")";
                    break;

            }

            if (mbrDef.BoundMemberIsStatic)
            {
                qualifier = mbrDef.BoundMemberTypeName;
            }
            else if (!noThis)
            {
                qualifier = "this";
            }

            return null;
        }
    }
}
